from django.shortcuts import render
from QQLoginTool.QQtool import OAuthQQ
from django.conf import settings
from django import http
from django.views import View
from apps.oauth.models import OAuthQQUser
import logging, json, re
logger = logging.getLogger('django')
from django.contrib.auth import login
from apps.oauth.utils import generate_access_token_openid, check_access_token_openid
from django_redis import get_redis_connection
from apps.users.models import User
from django.db import DatabaseError



# Create your views here.


class QQUserView(View):
    """用户扫码登录的回调处理
    GET: /oauth_callback/
    """

    def get(self, request):
        """处理授权后的回调逻辑"""

        # 获取前段发送过来的 code 参数
        code = request.GET.get('code')

        if not code:
            # 判断 code 参数是否存在
            return http.JsonResponse({'code': 400, 'errmsg': '缺少code参数'})

        # 调用我们安装的QQLoginTool 工具类
        # 创建工具对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_CLIENT_URI)

        try:
            # 携带 code 向QQ服务器请求 access_token
            access_token = oauth.get_access_token(code)

            # 携带access_token 向QQ服务器请求openid
            openid = oauth.get_open_id(access_token)
        except Exception as e:
            # 如果上面获取openid 出错，则验证失败
            logger.error(e)
            # 返回结果
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'oauth2.0认证失败，即获取qq信息失败'})
        # 使用openid去判断当前的QQ用户是否已经绑定过美多商城的用户
        try:
            oauth_model = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # openid未绑定美多商城的用户，将用户引导到绑定用户的页面
            # 工作中会规定很多的状态码，而每个状态码都对应一种操作结果
            # 在美多商城中如果QQ用户未绑定美多商城用户，通过状态码300告诉前段，让他根据需求文档做响应的处理
            # 为了简单处理，我们将openid还给用户自己保存，将来在绑定用户时，前段再传给我们即可

            # 转化openid为密文
            access_token_openid = generate_access_token_openid(openid)

            return http.JsonResponse({'code': 300, 'errmsg': '用户未绑定', 'access_token': access_token_openid})


        else:
            # openid 已绑定美多商城的用户， 直接实现状态保持即可
            # 提示:在实现QQ登录时，真正登录到美多商城的不是QQ用户，而是QQ用户绑定的美多商城用户
            # login(request=request, user='跟openid绑定的美多商城的用户对象')
            login(request=request, user=oauth_model.user)

            # 通过设置cookie 进行首页用户名展示
            response = http.JsonResponse({'code': 0, 'errmsg': 'ok'})
            response.set_cookie('username', oauth_model.user.username, max_age=3600*24*14)

            return response

    def post(self,request):
        """实现openid绑定用户的逻辑"""

        # 接受参数
        json_dict = json.loads(request.body.decode())

        mobile = json_dict.get('mobile')
        password = json_dict.get('password')
        sms_code_client = json_dict.get('sms_code')
        access_token = json_dict.get('access_token')

        # 校验参数
        if not all([mobile,password,sms_code_client,access_token]):
            return http.JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})

        # 校验mobile
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'mobile格式错误'})
        # 校验password
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'password格式有误'})

        # 校验sms_code
        # 1.链接redis数据库
        redis_conn = get_redis_connection('verify_code')

        # 2.从redis中取值
        sms_code_server = redis_conn.get('sms_%s' % mobile)

        # 3.判断该值是否存在
        if not sms_code_server:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '短信验证码过期'})

        # 4.对比redis中取出的值和前端发的值
        if sms_code_client != sms_code_server.decode():
            return http.JsonResponse({'code': 400,
                                      'errmsg': '验证码错误'})

        # 校验openid
        openid = check_access_token_openid(access_token)
        if not openid:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数openid有误'})

        # 判断手机好对应的用户是否存在
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 如果手机好对应的用户不存在，则新建用户
            user = User.objects.create_user(username=mobile,
                                            password=password,
                                            mobile=mobile)
        else:
            # 如果手机好对应的用户存在，校验密码
            if not user.check_password(password):
                return http.JsonResponse({'code': 400, 'errmsg': '密码不正确'})


        # 将上面得到的用户跟openid进行绑定
        try:
            OAuthQQUser.objects.create(user=user, openid=openid)
        except Exception as e:
            return http.JsonResponse({'code': 400, 'errmsg': '往数据库添加数据出错'})

        # 实现状态保持
        login(request=request, user=user)

        # 响应结果
        response = http.JsonResponse({'code': 0, 'errmsg': 'ok'})

        response.set_cookie('username', user.username, max_age=3600*24*14)

        return response





class QQURLView(View):
    """提供QQ登录页面网址
    GET: /qq/authorization/"""

    def get(self, request):
        """提供QQ登录扫码链接"""
        # next 表示从哪个页面进入到登录页面
        # 将来登录成功后，就自动回到那个页面
        next = request.GET.get('next','/')

        # 获取QQ登录页面网址
        # 创建OAuthQQ类的对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_CLIENT_URI,
                        state=next)

        # 调用对象的获取 qq 地址方法
        login_url = oauth.get_qq_url()

        # 返回登录地址
        return http.JsonResponse({'code': 0,
                                  'errmsg': 'ok',
                                  'login_url': login_url})
